package com.dtcnet.skmvp.utils;

import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;

import com.dtcnet.skmvp.base.BaseApplication;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.RandomAccessFile;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;

/**
 * @author duany
 */
public class Log2f {

    public static final String TAG = "Log2f";

    /**
     * 文件写入地址
     */
    public static String LOG_PATH = null;

    /**
     * 文件最大大小 （1024 * 1024 = 1MB）
     */
    public static long MAX_SIZE = 1024 * 1024;

    /**
     * 是否写入文件
     */
    public static boolean LOG_FILE = true;

    /**
     * 是否打印到控制台
     */
    public static boolean LOG_CAT = true;

    /**
     * 清理三十天前的日志，如果小于等于0则不清理
     */
    public static int CLEAN_DAY = 30;

    public static void v(String m) {
        Map<String, String> classInfo = getClassInfo();
        if (LOG_CAT) {
            Log.v(TAG, classInfo.get("LOG_CAT") + m);
        }
        if (LOG_FILE) {
            write("V", classInfo.get("LOG_FILE"), m);
        }
    }

    public static void i(String m) {
        Map<String, String> classInfo = getClassInfo();
        if (LOG_CAT) {
            Log.i(TAG, classInfo.get("LOG_CAT") + m);
        }
        if (LOG_FILE) {
            write("I", classInfo.get("LOG_FILE"), m);
        }
    }

    public static void d(String m) {
        Map<String, String> classInfo = getClassInfo();
        if (LOG_CAT) {
            Log.d(TAG, classInfo.get("LOG_CAT") + m);
        }
        if (LOG_FILE) {
            write("D", classInfo.get("LOG_FILE"), m);
        }
    }

    public static void w(String m) {
        Map<String, String> classInfo = getClassInfo();
        if (LOG_CAT) {
            Log.w(TAG, classInfo.get("LOG_CAT") + m);
        }
        if (LOG_FILE) {
            write("W", classInfo.get("LOG_FILE"), m);
        }
    }

    public static void w(Throwable t) {
        Map<String, String> classInfo = getClassInfo();
        if (LOG_CAT) {
            Log.w(TAG, classInfo.get("LOG_CAT") + exception(t));
        }
        if (LOG_FILE) {
            write("W", classInfo.get("LOG_FILE"), exception(t));
        }
    }

    public static void e(String m) {
        Map<String, String> classInfo = getClassInfo();
        if (LOG_CAT) {
            Log.e(TAG, classInfo.get("LOG_CAT") + m);
        }
        if (LOG_FILE) {
            write("E", classInfo.get("LOG_FILE"), m);
        }
    }

    public static void e(Throwable t) {
        Map<String, String> classInfo = getClassInfo();
        if (LOG_CAT) {
            Log.e(TAG, classInfo.get("LOG_CAT") + exception(t));
        }
        if (LOG_FILE) {
            write("E", classInfo.get("LOG_FILE"), exception(t));
        }
    }

    private static void write(String tag, String classInfo, String content) {
        if (TextUtils.isEmpty(LOG_PATH)) {
            // 设置默认日志路径
            LOG_PATH = BaseApplication.getContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getPath();
        }
        String log = String.format("%s %s/%s: %s", getNow("yyyy-MM-dd HH:mm:ss.SSS"), tag, classInfo, content);
        writeTxtToFile(log, LOG_PATH + "/log/", getNow("yyyy-MM-dd") + ".txt");
    }

    private static String getNow(String like) {
        SimpleDateFormat sdr = new SimpleDateFormat(like, Locale.getDefault());
        return sdr.format(Calendar.getInstance().getTime());
    }

    private static Map<String, String> getClassInfo() {
        Map<String, String> map = new HashMap<>();
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        if (stackTrace.length < 5) {
            map.put("LOG_CAT", String.format("<Thread:%s/())>: ", Thread.currentThread().getName()));
            map.put("LOG_FILE", String.format("[Thread:%s >> ()]", Thread.currentThread().getName()));
            return map;
        }
        StackTraceElement targetElement = stackTrace[4];
        String className = targetElement.getClassName();
        String methodName = targetElement.getMethodName();
        String fileName = targetElement.getFileName();
        int lineNumber = targetElement.getLineNumber();
        map.put("LOG_CAT", String.format(Locale.CHINA, "<Thread:%s/(%s:%d)>: ", Thread.currentThread().getName(), fileName, lineNumber));
        map.put("LOG_FILE", String.format(Locale.CHINA, "[Thread:%s >> %s.%s(%s:%d)]", Thread.currentThread().getName(), className, methodName, fileName, lineNumber));
        return map;
    }

    /**
     * 将异常信息转化成字符串
     *
     * @param t Throwable
     * @return 异常
     */
    private static String exception(Throwable t) {
        if (t == null) {
            return null;
        }
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            t.printStackTrace(new PrintStream(stream));
        } finally {
            try {
                stream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return stream.toString();
    }

    /**
     * 将字符串写入到文本文件中
     *
     * @param message  写入的文本
     * @param filePath 文件路径
     * @param fileName 文件名
     */
    private static void writeTxtToFile(String message, String filePath, String fileName) {
        // 每次写入时，都换行写
        message += "\r\n";
        try {
            File file = makeFilePath(filePath, fileName);
            if (file == null) {
                return;
            }
            RandomAccessFile raf = new RandomAccessFile(file, "rwd");
            raf.seek(file.length());
            raf.write(message.getBytes());
            raf.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成文件，如果没有文件夹则创建
     *
     * @param filePath 文件夹路径
     * @param fileName 文件夹名称
     * @return 文件路径
     */
    private static File makeFilePath(String filePath, String fileName) {
        try {
            // 日期命名的文件夹
            File folder = new File(filePath + fileName);
            if (!folder.exists()) {
                if (createPath(folder.getPath())) {
                    File logFile = new File(filePath + fileName + "/1.txt");
                    if (logFile.createNewFile()) {
                        return logFile;
                    }
                }
            } else {
                File logFile = null;

                File[] files = folder.listFiles();
                String logFileName = null;
                if (files == null || files.length == 0) {
                    logFileName = "/1.txt";
                    logFile = new File(folder.getPath() + logFileName);
                } else {
                    // 获取文件夹最后一个文件
                    logFile = files[files.length - 1];

                    if (logFile.length() > MAX_SIZE) {
                        // 文件大小超过100k，则重新命名
                        logFileName = "/" + (files.length + 1) + ".txt";
                        logFile = new File(folder.getPath() + logFileName);
                    }
                }

                if (!logFile.exists()) {
                    if (logFile.createNewFile()) {
                        return logFile;
                    }
                }
                return logFile;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 创建多级目录
     *
     * @param filePath 目录
     * @return 创建完成
     */
    private static boolean createPath(String filePath) {
        try {
            File file = new File(filePath);
            if (file.exists()) {
                return true;
            } else {
                if (file.getParentFile() == null || file.getParentFile().exists()) {
                    return file.mkdirs();
                } else {
                    // 创建上级目录
                    return createPath(file.getParent());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 清理之前的日志
     */
    public static void cleanLog() {
        if (CLEAN_DAY <= 0) {
            return;
        }
        if (TextUtils.isEmpty(LOG_PATH)) {
            // 设置默认日志路径
            LOG_PATH = BaseApplication.getContext().getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS).getPath();
        }

        // 获取文件夹下的所有文件
        File doc = new File(LOG_PATH + "/log");
        if (!doc.exists()) {
            return;
        }

        // 获取所有的日志文件
        File[] logs = doc.listFiles();
        if (logs == null) {
            return;
        }

        // 日期格式化对象
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);

        long nowTime = Calendar.getInstance().getTimeInMillis();
        long dayTime = 1000 * 60 * 60 * 24;
        for (File logFolder : logs) {
            // 将文件名转为日期
            try {
                Date date = format.parse(logFolder.getName().replace(".txt", ""));
                if (date != null) {
                    // 判断日期相减是否大于CLEAN_DAY
                    if ((nowTime - date.getTime()) / dayTime > CLEAN_DAY) {
                        // 删除文件夹
                        deleteFolder(logFolder.getPath());
                    }
                }
            } catch (ParseException e) {
                e.printStackTrace();
                Log2f.e(e);
            }
        }
    }

    /**
     * 删除指定目录
     *
     * @param path 文件路径
     */
    public static void deleteFolder(String path) {
        if (!TextUtils.isEmpty(path)) {
            try {
                File file = new File(path);
                if (file.isDirectory()) {
                    File files[] = file.listFiles();
                    for (File file1 : files) {
                        deleteFolder(file1.getAbsolutePath());
                    }
                }
                if (!file.isDirectory()) {
                    file.delete();
                } else {
                    if (Objects.requireNonNull(file.listFiles()).length == 0) {
                        file.delete();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
